//
// Created by Tony on 2024/6/23.
//

#ifndef TLANG_CODE_H
#define TLANG_CODE_H

#include "../../common/OpCode.h"
#include <cstdint>
#include <memory>
#include <string>
#include <vector>

namespace RtCode {

using Common::OpCode;
using std::enable_shared_from_this;
using std::string;
using std::vector;

class Code : public enable_shared_from_this<Code> {
    vector<uint8_t> mCode;
    uint16_t mMaxStack{};
    uint16_t mMaxLocals{};

    // status
    bool mHasReturn{false};
    uint16_t mTop{};

    union Union16 {
        struct {
            uint8_t hu8;
            uint8_t lu8;
        };
        uint16_t u16;
        int16_t i16;
    };

    union Union32 {
        struct {
            uint16_t hu16;
            uint16_t lu16;
        };
        uint32_t u32;
        int32_t i32;
    };

public:
    Code() = default;

    int32_t addOpCode(OpCode opcode);

    void addOperandUint16(uint16_t operand);
    void addOperandInt16(int16_t operand);

    void updateOperandUint16(int32_t index, uint16_t operand);
    void updateOperandInt16(int32_t index, int16_t operand);

    int32_t addOpCodeWithUint16(OpCode opcode, uint16_t operand);
    int32_t addOpCodeWithInt16(OpCode opcode, int16_t operand);

    int32_t size() const { return static_cast<int32_t>(mCode.size()); }
    const vector<uint8_t>& getCode() const;

    uint8_t readUint8(uint32_t index) const;
    uint16_t readUint16(uint32_t index) const;
    int16_t readInt16(uint32_t index) const;

    void setLocalSlotCount(uint16_t maxLocals);
    uint16_t getLocalSlotCount() const;
    uint16_t getMaxStack() const;
    uint16_t top() const { return mTop; }
    uint16_t incTop(uint16_t i = 1);
    uint16_t decTop(uint16_t i = 1);

    bool hasReturn() const;

    string toString();
};

} // namespace RtCode

#endif // TLANG_CODE_H
